package com.han.nettytestdemo.connector.netty.client;

import android.util.Log;

import com.han.nettytestdemo.connector.netty.intf.ConnectClientCallback;
import com.han.nettytestdemo.connector.netty.intf.MessageClientCallback;

import java.net.InetSocketAddress;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class NettyClient {

    private static final String TAG = "NettyClient";
    //    private final int PORT = 18000;
    private int PORT = 9856;
    //    private final int PORT = 7010;
//    private final String IP = "192.168.2.58";
    private String IP = "192.168.1.248";
    //    private final String IP = "192.168.2.188";
    //        private final String IP = "192.168.8.156";
    private static NettyClient nettyClient;
    private Channel channel;
    private ChannelFuture channelFuture;
    private MessageClientCallback messageClientCallback;
    private ConnectClientCallback connectCallback;

    private ClientHandler clientHandler;

    public static NettyClient getInstance() {
        if (nettyClient == null) {
            nettyClient = new NettyClient();
        }
        return nettyClient;
    }

    /**
     * 设置Ip和端口号
     *
     * @param ip
     * @param port
     */
    public void setIPAndPort(String ip, int port) {
        this.IP = ip;
        this.PORT = port;
    }

    /**
     * 需要在子线程中发起连接
     */
    public void connectNetty() {
        new Thread(() -> connect()).start();
    }

    /**
     * 获取与服务端的连接
     */
    public static Channel getChannel() {
        if (nettyClient == null) {
            return null;
        }
        return nettyClient.channel;
    }

    private NioEventLoopGroup group;
    private Bootstrap bootstrap;

    /**
     * 连接服务端
     */
    private void connect() {
        try {
            if (group == null) {
                group = new NioEventLoopGroup();
            }
            if (bootstrap == null) {
                bootstrap = new Bootstrap()
                        // 指定channel类型
                        .channel(NioSocketChannel.class)
                        // 指定EventLoopGroup
                        .group(group)
                        // 指定Handler
                        .handler(new ChannelInitializer<SocketChannel>() {

                            @Override
                            protected void initChannel(SocketChannel socketChannel) throws Exception {
                                //分隔符
//                                ByteBuf delimiter = Unpooled.copiedBuffer("$".getBytes());
                                ChannelPipeline pipeline = socketChannel.pipeline();
                                //解决粘包
//                                pipeline.addLast(new DelimiterBasedFrameDecoder(65535, delimiter));

                                // 对经过粘包和拆包处理之后的数据进行json反序列化，从而得到User对象
                                pipeline.addLast(new JsonDecoder());
                                // 对响应数据进行编码，主要是将User对象序列化为json
                                pipeline.addLast(new JsonEncoder());
                                //添加数据处理器
                                clientHandler = new ClientHandler(NettyClient.this,
                                        connectCallback);
                                pipeline.addLast(clientHandler);
                            }
                        });
            }
            // 连接到服务端
            channelFuture = bootstrap.connect(new InetSocketAddress(IP, PORT));
            // 添加连接状态监听
            channelFuture.addListener(new ConnectListener(this));
            //获取连接通道
            channel = channelFuture.sync().channel();
            if (null != connectCallback) {
                connectCallback.onConnect(0, "连接成功");
            }
        } catch (Exception e) {
            if (null != connectCallback) {
                connectCallback.onConnect(1, "连接失败");
            }
            Log.e(TAG, "连接失败：" + e.getMessage());
            e.printStackTrace();
        }
    }

    public void disConnect() {
        if (channelFuture != null && channelFuture.channel() != null) {
            channelFuture.channel().close();
        }
    }

    public void destroy() {
        if (channelFuture != null && channelFuture.channel() != null) {
            channelFuture.channel().close();
            channelFuture.channel().eventLoop().shutdownGracefully();
        }
    }

    public void setMessageClientCallback(MessageClientCallback messageClientCallback) {
        this.messageClientCallback = messageClientCallback;
        if (null != clientHandler) {
            clientHandler.setMessageClientCallback(messageClientCallback);
        }
    }

    public void setConnectClientCallback(ConnectClientCallback connectCallback) {
        this.connectCallback = connectCallback;
    }
}
